home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PRINTER / JPSRC11.ARJ / JETL2D.C < prev    next >
C/C++ Source or Header  |  1991-08-04  |  28KB  |  845 lines

  1. /*
  2.  *      JET PAK - HP DeskJet and LaserJet series printer utilities
  3.  *
  4.  *      JETL2D program - convert from LaserJet to DeskJet soft font file
  5.  *
  6.  *      Version 1.1 (Public Domain)
  7.  */
  8.  
  9. /* system include files */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14.  
  15. /* application include files */
  16. #include "patchlev.h"
  17. #include "jetfont.h"
  18. #include "jetutil.h"
  19. #include "jetbmp.h"
  20.  
  21. /*
  22.  *  MODULE GLOBAL DATA
  23.  */
  24.  
  25. /* baseline distance for bottom pass */
  26. static UNSIGNEDINT baseline;
  27.  
  28. /* pitch is needed for converting landscape characters */
  29. static UNSIGNEDINT pitch;
  30.  
  31. /* portrait or landscape font */
  32. static UNSIGNEDBYTE orientation;
  33.  
  34. /* fixed or proportional spacing font */
  35. static UNSIGNEDINT spacing;
  36.  
  37. /* DJ, DJ+ or DJ500 output character format */
  38. static UNSIGNEDBYTE charformat;
  39.  
  40. /* input and output font commands being processed */
  41. static FONT_COMMAND infc, outfc;
  42.  
  43. /* output file suffix */
  44. static char output_suffix[SUFFIX_MAX] = ".l2d";
  45.  
  46. /* DJ500 support required? */
  47. static BOOLEAN dj500_support = TRUE;
  48.  
  49. /* bitmap optimisation required? */
  50. static BOOLEAN bitmap_optimisation = TRUE;
  51.  
  52. /* bitmap optimisation null smoothing data */
  53. static UNSIGNEDBYTE *smooth_null = NULL;
  54.  
  55. /* record the worst side bearing loss to left and right */
  56. static SIGNEDINT worst_left_loss, worst_right_loss;
  57. static UNSIGNEDINT worst_left_char, worst_right_char;
  58.  
  59. /* compact bitmap structure */
  60. typedef struct compact_ljchar_struct {
  61.     SIGNEDINT    left_offset;
  62.     SIGNEDINT    top_offset;
  63.     UNSIGNEDINT  character_width;
  64.     UNSIGNEDINT  character_height;
  65.     SIGNEDINT    delta_x;
  66.     UNSIGNEDBYTE *bitmap;
  67.     UNSIGNEDBYTE *smooth;
  68. } COMPACT_LJCHAR;
  69. static COMPACT_LJCHAR ljchars[256] = { 0 };
  70. #define sizeofljbitmap(w,h) (((w + 7)/8)*h)
  71.  
  72. /*
  73.  * LOCAL FUNCTIONS
  74.  */
  75.  
  76. static void usage_wrong()
  77. {
  78.     /*
  79.      * Print usage message and exit.
  80.      */
  81.     fprintf(stderr, USAGE_HEADER);
  82.     fprintf(stderr, "Usage: JETL2D [-h] [-j] [-o] [-t filetype] ljfontfile [ljfontfile...]\n\n");
  83.     fprintf(stderr, "Convert LaserJet font files to DeskJet format\n\n");
  84.     fprintf(stderr, "  -h            print this usage information\n");
  85.     fprintf(stderr, "  -j            disable bitmap smoothing\n");
  86.     fprintf(stderr, "  -o            disable DJ500 support\n");
  87.     fprintf(stderr, "  -t filetype   change output file type (default %s)\n", output_suffix);
  88.     fprintf(stderr, "  ljfontfile    name of LaserJet format soft font file to be converted\n");
  89.     exit(1);
  90. }
  91.  
  92. static int ljchar_create(charcode, infcp)
  93. UNSIGNEDINT charcode;
  94. FONT_COMMAND *infcp;
  95. {
  96.     /*
  97.      * Save the information in a LaserJet character descriptor to
  98.      * a compact LaserJet character structure
  99.      */
  100.     struct ljchar_struct *ljp;
  101.  
  102.     /* issue a warning if the character descriptor is in a strange format */
  103.     if (infcp->data.character.format != LJCHARFORMAT)
  104.         fprintf(stderr, WARNING_BAD_CHAR_FORMAT,
  105.                 os_dir, os_file, infcp->data.character.format);
  106.  
  107.     /* check for a character width or height bigger than can be supported
  108.        on the DJ */
  109.     if (    (infcp->data.character.data.ljchar.character_width*2 > MAX_CELL_WIDTH)
  110.          || (infcp->data.character.data.ljchar.character_height > MAX_CELL_HEIGHT) )
  111.     {
  112.         fprintf(stderr, ERROR_BITMAP_TOO_BIG, os_dir, os_file);
  113.         return(ERROR);
  114.     }
  115.  
  116.     /* check this isn't a continuation */
  117.     if (infcp->data.character.continuation != 0)
  118.     {
  119.         fprintf(stderr, ERROR_CONTINUATION, os_dir, os_file);
  120.         return(ERROR);
  121.     }
  122.  
  123.     /* check the character code is in range */
  124.     if (charcode >= sizeofarray(ljchars))
  125.     {
  126.         fprintf(stderr, ERROR_CODE_TOO_BIG, os_dir, os_file, charcode);
  127.         return(ERROR);
  128.     }
  129.  
  130.     /* OK to save the information */
  131.     ljp = &infcp->data.character.data.ljchar;
  132.     ljchars[charcode].left_offset = ljp->left_offset;
  133.     ljchars[charcode].top_offset = ljp->top_offset;
  134.     ljchars[charcode].character_width = ljp->character_width;
  135.     ljchars[charcode].character_height = ljp->character_height;
  136.  
  137.     /* for fixed fonts, derive the character escapement from the
  138.        pitch: the delta X value is sometimes invalid */
  139.     if (spacing == FIXED)
  140.         ljchars[charcode].delta_x = pitch*4;
  141.     else
  142.         ljchars[charcode].delta_x = ljp->delta_x;
  143.  
  144.     if ((ljchars[charcode].bitmap =
  145.         zalloc(sizeofljbitmap(ljp->character_width, ljp->character_height))) == NULL)
  146.     {
  147.         fprintf(stderr, ERROR_FONT_OUT_OF_HEAP, os_dir, os_file);
  148.         return(ERROR);
  149.     }
  150.     memcpy(ljchars[charcode].bitmap, ljp->bitmap,
  151.             sizeofljbitmap(ljp->character_width, ljp->character_height));
  152.     if (bitmap_optimisation)
  153.     {
  154.         if ((ljchars[charcode].smooth =
  155.             zalloc(sizeofljbitmap(ljp->character_width, ljp->character_height))) == NULL)
  156.         {
  157.             fprintf(stderr, ERROR_FONT_OUT_OF_HEAP, os_dir, os_file);
  158.             return(ERROR);
  159.         }
  160.         if (bitmap_smooth(ljchars[charcode].bitmap, ljchars[charcode].smooth, ljp->character_width, ljp->character_height) == ERROR)
  161.         {
  162.             fprintf(stderr, ERROR_FONT_OUT_OF_HEAP, os_dir, os_file);
  163.             return(ERROR);
  164.         }
  165.     }
  166.     else
  167.     {
  168.         if (smooth_null == NULL)
  169.         {
  170.             /* allocate and zeroise null smoothing data */
  171.             if ((smooth_null = zalloc(BITMAP_SIZE_MAX)) == NULL)
  172.             {
  173.                 fprintf(stderr, ERROR_FONT_OUT_OF_HEAP, os_dir, os_file);
  174.                 return(ERROR);
  175.             }
  176.         }
  177.  
  178.         /* point smoothing data for all bitmaps at same data */
  179.         ljchars[charcode].smooth = smooth_null;
  180.     }
  181.  
  182.     return(OK);
  183. }
  184.  
  185. static void ljchar_free_all()
  186. {
  187.     /*
  188.      * Free the resources used in all the compact LaserJet characters.
  189.      */
  190.     UNSIGNEDINT charcode;
  191.  
  192.     for (charcode = 0; charcode < sizeofarray(ljchars); charcode++)
  193.     {
  194.         if (ljchars[charcode].bitmap != NULL)
  195.         {
  196.             free(ljchars[charcode].bitmap);
  197.             ljchars[charcode].bitmap = NULL;
  198.         }
  199.         if (bitmap_optimisation)
  200.         {
  201.             if (ljchars[charcode].smooth != NULL)
  202.             {
  203.                 free(ljchars[charcode].smooth);
  204.                 ljchars[charcode].smooth = NULL;
  205.             }
  206.         }
  207.         else
  208.         {
  209.             if (smooth_null != NULL)
  210.             {
  211.                 free(smooth_null);
  212.                 smooth_null = NULL;
  213.             }
  214.  
  215.             ljchars[charcode].smooth = NULL;
  216.         }
  217.     }
  218. }
  219.  
  220. static int fdc_lj_to_dj(infcp, outfcp)
  221. FONT_COMMAND *infcp, *outfcp;
  222. {
  223.     /*
  224.      * Convert a LaserJet font descriptor command to a DeskJet font
  225.      * descriptor command.
  226.      *
  227.      * In the output Deskjet fonts, the nominal design cell expands to
  228.      * fill an integral number of printer head passes, with the bitmap
  229.      * data shifting down, so the bottom of the LJ design cell aligns
  230.      * with the bottom of the DJ design cell.
  231.      *
  232.      * The resulting baseline position relative to the origin of the
  233.      * bottom DJ pass is saved in 'baseline'. Baselines for the other
  234.      * passes can be derived from this by adding MULTI_PASS_OFFSET
  235.      * for each pass.
  236.      *
  237.      * 'charformat', 'pitch' and orientation save additional header
  238.      * information required during character descriptor processing.
  239.      *
  240.      * The number of passes required in the DJ font is returned.
  241.      */
  242.     int passes;
  243.     FONT_DESCRIPTOR *fdp;
  244.     int i;
  245.  
  246.     /* check input file is in correct format */
  247.     if (    (infcp->data.font.header_format == DJFONTFORMAT)
  248.          || (infcp->data.font.header_format == DJPFONTFORMAT)
  249.          || (infcp->data.font.header_format == DJ500FONTFORMAT) )
  250.     {
  251.         fprintf(stderr, ERROR_DESKJET, os_dir, os_file);
  252.         return(ERROR);
  253.     }
  254.     else if (infcp->data.font.header_format != LJFONTFORMAT)
  255.     {
  256.         fprintf(stderr, WARNING_BAD_FONT_FORMAT,
  257.                 os_dir, os_file, infcp->data.font.header_format);
  258.     }
  259.  
  260.     outfcp->command_type = infcp->command_type;
  261.     if (dj500_support)
  262.         outfcp->number = DJ500FDSIZE+DJ500SSIZE;
  263.     else
  264.         outfcp->number = DJFDSIZE+DJSSIZE;
  265.  
  266.  
  267.     /* most of the font descriptor fields can be copied straight
  268.        across; a lot of LaserJet fonts have junk in many of the
  269.        fields, so this will be garbage-in-garbage-out; however, that
  270.        seems to be OK since most of the affected fields aren't used
  271.        by the DJ either */
  272.     outfcp->data.font = infcp->data.font;
  273.  
  274.     /* now change the standard font descriptor bits that are different */
  275.     fdp = &outfcp->data.font;
  276.     if (dj500_support)
  277.         fdp->size = DJ500FDSIZE;
  278.     else
  279.         fdp->size = DJFDSIZE;
  280.  
  281.     /* quality is best set to Letter Quality, so that algorithmic
  282.        draft is used for the font if the printer is set to NLQ or
  283.        Draft mode. Most LJ fonts will have 0 for this field: if this
  284.        is just copied over, the font would always be printed "as is"
  285.        regardless of what quality the user selected */
  286.     fdp->quality = 2;
  287.  
  288.     /* placement must be normal (ie not super- or sub- script) */
  289.     fdp->placement = 0;
  290.  
  291.     /* last code is used on the DJ and should have a reasonable upper limit value */
  292.     if (fdp->type == FONT_TYPE_7BIT)
  293.         fdp->last_code = 127;
  294.     else
  295.         fdp->last_code = 255;
  296.  
  297.     /* add the extended font descriptor bits ... */
  298.     fdp->h_pixel_resolution = 600;
  299.     fdp->v_pixel_resolution = 300;
  300.  
  301.     /* initialise multi-pass baseline offsets - may be overridden */
  302.     fdp->baseline_offset_2 = 0;
  303.     fdp->baseline_offset_3 = 0;
  304.     fdp->baseline_offset_4 = 0;
  305.  
  306.     /* convert the bitmap related data - depends on orientation */
  307.     if (fdp->orientation == LANDSCAPE)
  308.     {
  309.         fdp->cell_height *= 2;  /* -> 600 dpi in X direction */
  310.  
  311.         /* only fixed width fonts are supported in landscape mode */
  312.         if (fdp->spacing != FIXED)
  313.         {
  314.             fprintf(stderr, ERROR_LANDSCAPE_FIXED, os_dir, os_file);
  315.             return(ERROR);
  316.         }
  317.  
  318.         /* fixed character width must be printable in one head pass */
  319.         if (fdp->pitch > PASS_HEIGHT*4)
  320.         {
  321.             fprintf(stderr, ERROR_FONT_TOO_BIG, os_dir, os_file);
  322.             return(ERROR);
  323.         }
  324.  
  325.         /* one pass required */
  326.         passes = 1;
  327.  
  328.         /* EMPIRICAL HACK FOLLOWS: this is done to ensure the soft
  329.            font character's baseline align correctly with other
  330.            landscape fonts. The baseline offsets themselves don't
  331.            seem to be important but the difference is: the difference
  332.            must be equal to the baseline distance in 300 dpi units.
  333.            I can only guess at why this should be, since it isn't
  334.            explained in the manual, and I've not seen any real
  335.            landscape soft fonts for the DJ+ for comparision. */
  336.         fdp->baseline_offset_2 = fdp->baseline_distance*2;
  337.     }
  338.     else    /* PORTRAIT */
  339.     {
  340.         fdp->cell_width *= 2;   /* -> 600 dpi in X direction */
  341.  
  342.         /* now deal with splitting the design cell up into multiple passes */
  343.         passes = 1 + (fdp->cell_height - 1 - PASS_OVERLAP)/MULTI_PASS_OFFSET;
  344.  
  345.         /* check for design cells bigger than can be supported on the DJ */
  346.         if (passes > 4)
  347.         {
  348.             fprintf(stderr, ERROR_FONT_TOO_BIG, os_dir, os_file);
  349.             return(ERROR);
  350.         }
  351.  
  352.         /* shift the LJ baseline so the bottom of the DJ cell aligns
  353.            with the bottom of the bottom pass */
  354.         fdp->baseline_distance +=   (MULTI_PASS_OFFSET*passes + PASS_OVERLAP)
  355.                                   - fdp->cell_height;
  356.         fdp->cell_height = passes * PASS_HEIGHT;
  357.  
  358.         /* now fix up the baselines for all the passes */
  359.         switch (passes)
  360.         {
  361.                                 /* !! intended drop-throughs !! */
  362.         case 4:
  363.             fdp->baseline_offset_4 = fdp->baseline_distance;
  364.             fdp->baseline_distance -= MULTI_PASS_OFFSET;
  365.         case 3:
  366.             fdp->baseline_offset_3 = fdp->baseline_distance;
  367.             fdp->baseline_distance -= MULTI_PASS_OFFSET;
  368.         case 2:
  369.             fdp->baseline_offset_2 = fdp->baseline_distance;
  370.             fdp->baseline_distance -= MULTI_PASS_OFFSET;
  371.         }
  372.     }
  373.  
  374.     /* fix up out-of-range underline parameters */
  375.     if (    (((SIGNEDBYTE)fdp->baseline_distance - fdp->underline_distance) <= UNDERLINE_MIN)
  376.          || (((SIGNEDBYTE)fdp->baseline_distance - fdp->underline_distance + (SIGNEDBYTE)fdp->underline_height) > UNDERLINE_MAX) )
  377.     {
  378.         fdp->underline_height = underline_height_for_height(fdp->height);
  379.         fdp->underline_distance =   (SIGNEDBYTE)fdp->baseline_distance
  380.                                   + (SIGNEDBYTE)fdp->underline_height
  381.                                   - (SIGNEDBYTE)UNDERLINE_MAX;
  382.     }
  383.  
  384.     /* add the printer specific font bits ... */
  385.     if (dj500_support)
  386.         fdp->specific_size = DJ500SSIZE;
  387.     else
  388.         fdp->specific_size = DJSSIZE;
  389.  
  390.         /* ... this may be used by soft font downloaders, but not by the
  391.            printer - it's too much hassle to fix up right now */
  392.     fdp->data_size = 0;
  393.  
  394.         /* ... half pitch mustn't be allowed for proportional fonts */
  395.     if (fdp->spacing == FIXED)
  396.         fdp->no_half_pitch = 0;
  397.     else
  398.         fdp->no_half_pitch = 1;
  399.  
  400.         /* ... 0 is a safe default for all these fields */
  401.     fdp->compressed = 0;
  402.     fdp->no_double_pitch = 0;
  403.     fdp->no_half_height = 0;
  404.     fdp->no_bold = 0;
  405.     fdp->no_draft = 0;
  406.     fdp->bold_method = 0;
  407.     fdp->reserved3 = 0;
  408.  
  409.         /* ... hold time factor should be set to 0 */
  410.     fdp->hold_time_factor = 0;
  411.  
  412.         /* ... include double underline parameters based on the single
  413.            underline parameters in the standard font descriptor */
  414.     fdp->bdu_height = (fdp->underline_height + 1)/2;
  415.     fdp->tdu_height = fdp->bdu_height;
  416.     fdp->bdu_distance =   fdp->underline_distance
  417.                         - (SIGNEDBYTE)fdp->underline_height
  418.                         + (SIGNEDBYTE)fdp->bdu_height;
  419.     fdp->tdu_distance =   fdp->bdu_distance
  420.                         + ((SIGNEDBYTE)fdp->bdu_height)*2;
  421.  
  422.     /* fill name extension with blanks */
  423.     for (i = 0; i < sizeof(fdp->name_extension); i++)
  424.         fdp->name_extension[i] = ' ';
  425.  
  426.     /* add identifying suffix to existing copyright notice */
  427.     if ((strlen(fdp->comment) + sizeof(JETL2D_COMMENT_SUFFIX)) < COMMENT_SIZE_MAX)
  428.         strcat(fdp->comment, JETL2D_COMMENT_SUFFIX);
  429.     outfcp->number += strlen(fdp->comment);
  430.  
  431.     /* save parameters needed in character descriptor processing */
  432.     baseline = fdp->baseline_distance;
  433.     pitch = fdp->pitch/4;
  434.     orientation = fdp->orientation;
  435.     spacing = fdp->spacing;
  436.  
  437.     /* play safe and force all multi-pass fonts to be unidirectional
  438.        to encourage better registration between the passes. Is there
  439.        a better way of working out what should go in this field? */
  440.     if (passes > 1)
  441.         fdp->unidirection = 1;
  442.     else
  443.         fdp->unidirection = 0;
  444.  
  445.     /* save the font and character format magic numbers */
  446.     if (dj500_support)
  447.     {
  448.         /* font only usable on DJ500 */
  449.         fprintf(stderr, WARNING_DJ500_ONLY, os_dir, os_file);
  450.         fdp->header_format = DJ500FONTFORMAT;
  451.         charformat = DJ500CHARFORMAT;
  452.     }
  453.     else if (orientation == LANDSCAPE)
  454.     {
  455.         /* landscape font - DeskJet+ printer only */
  456.         fprintf(stderr, WARNING_DJ_LANDSCAPE, os_dir, os_file);
  457.         fdp->header_format = DJPFONTFORMAT;
  458.         charformat = DJPCHARFORMAT;
  459.     }
  460.     else if (passes > 2)
  461.     {
  462.         /* > 98 dot cell height - DeskJet+ printer only */
  463.         fprintf(stderr, WARNING_DJ_TOO_LARGE, os_dir, os_file);
  464.         fdp->header_format = DJPFONTFORMAT;
  465.         charformat = DJPCHARFORMAT;
  466.     }
  467.     else
  468.     {
  469.         /* <= 98 dot cell height - any DeskJet series printer */
  470.         fdp->header_format = DJFONTFORMAT;
  471.         charformat = DJCHARFORMAT;
  472.     }
  473.  
  474.     return(passes);
  475. }
  476.  
  477. static int cdc_lj_to_dj(charcode, inccp, outfcp, char_type)
  478. UNSIGNEDINT charcode;
  479. COMPACT_LJCHAR *inccp;
  480. FONT_COMMAND *outfcp;
  481. int char_type;  /* single pass or pass number in multi-pass */
  482. {
  483.     /*
  484.      * Copy a compact LaserJet character and bitmap to
  485.      * a Deskjet character descriptor and bitmap command.
  486.      */
  487.     UNSIGNEDBYTE *data, *sdata;
  488.     int blanklines, datalines, pass, r;
  489.     struct djchar_struct *djp;
  490.     UNSIGNEDINT left_pad = 0, right_pad = 0;
  491.     SIGNEDINT left_offset, right_offset;
  492.  
  493.     outfcp->command_type = CDC;
  494.  
  495.     /* deal with the preamble bits */
  496.     outfcp->data.character.format = charformat;
  497.     outfcp->data.character.continuation = 0;
  498.  
  499.     /* deal with the character descriptor proper */
  500.     djp = &outfcp->data.character.data.djchar;
  501.     djp->descriptor_size = DJCDSIZE;
  502.     djp->char_type = char_type;
  503.     djp->character_width = inccp->character_width*2;  /* -> 600 dpi */
  504.  
  505.     /* positioning in X (raster scan) direction - depends on orientation */
  506.     if (orientation == LANDSCAPE)
  507.     {
  508.         /* the compressed width is reused as the left pad in landscape
  509.            fonts */
  510.         djp->comp_width = 2*(baseline+inccp->left_offset);
  511.         djp->left_offset = 0;
  512.         djp->right_offset = 0;
  513.     }
  514.     else    /* PORTRAIT */
  515.     {
  516.         djp->comp_width = 0;    /* no algorithmic compression */
  517.  
  518.         /* get the DJ left and right offsets in 600 dpi units */
  519.         left_offset = inccp->left_offset*2;
  520.         right_offset = inccp->delta_x/2 - left_offset - djp->character_width;
  521.  
  522.         if (spacing == FIXED)
  523.         {
  524.             /* left and right offset fields are ignored, horizontal
  525.                alignment must be done by padding the bitmap */
  526.             if (left_offset < right_offset)
  527.                 right_pad = (UNSIGNEDINT)(right_offset - left_offset);
  528.             else
  529.                 left_pad = (UNSIGNEDINT)(left_offset - right_offset);
  530.  
  531.             /* character width must be increased to take into account
  532.                the pad columns */
  533.             djp->character_width += (UNSIGNEDBYTE)(left_pad + right_pad);
  534.  
  535.             left_offset = 0;
  536.             right_offset = 0;
  537.         }
  538.  
  539.         if (dj500_support)
  540.         {
  541.             djp->left_offset = (SIGNEDBYTE)left_offset;
  542.             djp->right_offset = (SIGNEDBYTE)right_offset;
  543.         }
  544.         else
  545.         {
  546.             /* throw away any -ve side bearing - keep track of the worst
  547.                loss in 300 dpi units */
  548.             if (left_offset < 0)
  549.             {
  550.                 if (left_offset/2 < worst_left_loss)
  551.                 {
  552.                     worst_left_loss = left_offset/2;
  553.                     worst_left_char = charcode;
  554.                 }
  555.                 djp->left_offset = 0;
  556.             }
  557.             else
  558.             {
  559.                 djp->left_offset = (SIGNEDBYTE)left_offset;
  560.             }
  561.  
  562.             /* throw away any -ve side bearing - keep track of the worst
  563.                loss in 300 dpi units */
  564.             if (right_offset < 0)
  565.             {
  566.                 if (right_offset/2 < worst_right_loss)
  567.                 {
  568.                     worst_right_loss = right_offset/2;
  569.                     worst_right_char = charcode;
  570.                 }
  571.                 djp->right_offset = 0;
  572.             }
  573.             else
  574.             {
  575.                 djp->right_offset = (SIGNEDBYTE)right_offset;
  576.             }
  577.         }
  578.     }
  579.  
  580.     /* positioning in Y (paper motion) direction - depends on orientation */
  581.     if (orientation == LANDSCAPE)
  582.     {
  583.         blanklines = pitch - inccp->top_offset;
  584.         data = inccp->bitmap;
  585.         sdata = inccp->smooth;
  586.         datalines = inccp->character_height;
  587.         if (blanklines < 0)
  588.         {
  589.             data += ((inccp->character_width + 7)/8) * (-blanklines);
  590.             sdata += ((inccp->character_width + 7)/8) * (-blanklines);
  591.             datalines += blanklines;
  592.             blanklines = 0;
  593.         }
  594.         if (datalines > (pitch - blanklines))
  595.             datalines = pitch - blanklines;
  596.         if (datalines < 0)
  597.             datalines = 0;
  598.     }
  599.     else    /* PORTRAIT */
  600.     {
  601.         /* work out the number of blank lines preceding the pass data */
  602.         pass = pass_for_char_type(char_type);
  603.         blanklines =   (int)baseline
  604.                      + (int)pass*MULTI_PASS_OFFSET
  605.                      - (int)inccp->top_offset;
  606.         data = inccp->bitmap;
  607.         sdata = inccp->smooth;
  608.         if (blanklines < 0)
  609.         {
  610.             data += ((inccp->character_width + 7)/8) * (-blanklines);
  611.             sdata += ((inccp->character_width + 7)/8) * (-blanklines);
  612.             blanklines = 0;
  613.         }
  614.         else if (blanklines > lines_for_pass(pass))
  615.         {
  616.             blanklines = lines_for_pass(pass);
  617.         }
  618.  
  619.         /* work out the number of lines of bitmap data in the pass */
  620.         datalines =   (int)inccp->character_height
  621.                     + (int)baseline
  622.                     + (int)pass*MULTI_PASS_OFFSET
  623.                     - (int)inccp->top_offset;
  624.         if (datalines > (int)inccp->character_height)
  625.             datalines = (int)inccp->character_height;
  626.         if (datalines > (lines_for_pass(pass) - blanklines))
  627.             datalines = lines_for_pass(pass) - blanklines;
  628.         if (datalines < 0)
  629.             datalines = 0;
  630.     }
  631.  
  632.     /* now convert the bitmap itself */
  633.     if ((r = bitmap_lj_to_dj(data, sdata, inccp->character_width, datalines,
  634.                 blanklines, left_pad, right_pad, djp->bitmap,
  635.                 sizeof(djp->bitmap))) == ERROR)
  636.     {
  637.         fprintf(stderr, ERROR_BITMAP_TOO_BIG, os_dir, os_file);
  638.         return(ERROR);
  639.     }
  640.  
  641.     /* calculate the total number of bytes in descriptor */
  642.     outfcp->number = 2 + DJCDSIZE + r;
  643.  
  644.     return(OK);
  645. }
  646.  
  647. static void jetl2d()
  648. {
  649.     char inpath[OS_PATH_LEN], outpath[OS_PATH_LEN], *sp;
  650.     FILE *infp, *outfp;
  651.     int r, pass, npasses = 0;
  652.     char worst_char_string[10];
  653.     UNSIGNEDINT charcode;
  654.  
  655.     /* build the input and output file paths */
  656.     strcpy(inpath, os_dir);
  657.     strcat(inpath, os_file);
  658.     strcpy(outpath, os_file);
  659.     if ((sp = strrchr(outpath, '.')) == NULL)
  660.         strcat(outpath, output_suffix);
  661.     else
  662.         strcpy(sp, output_suffix);
  663.  
  664.     /* rudimentary check for input overwriting output */
  665.     if (strcmp(inpath, outpath) == 0)
  666.     {
  667.         fprintf(stderr, ERROR_OVERWRITE, os_dir, os_file);
  668.         return;
  669.     }
  670.  
  671.     if (!(infp = fopen(inpath, "rb")))
  672.     {
  673.         fprintf(stderr, ERROR_OPEN_READ_FAILED, os_dir, os_file);
  674.         return;
  675.     }
  676.     if (!(outfp = fopen(outpath, "wb")))
  677.     {
  678.         fprintf(stderr, ERROR_OPEN_WRITE_FAILED, os_dir, os_file, outpath);
  679.         fclose(infp);
  680.         return;
  681.     }
  682.  
  683.     /* initialise per input file data */
  684.     worst_left_loss = 0;
  685.     worst_right_loss = 0;
  686.  
  687.     /* copy the font header and load the characters into memory */
  688.     while ((r = font_command_read(infp, &infc)) == OK)
  689.     {
  690.         switch(infc.command_type)
  691.         {
  692.         case FDC:
  693.             if ((npasses = fdc_lj_to_dj(&infc, &outfc)) == ERROR)
  694.             {
  695.                 ljchar_free_all();
  696.                 fclose(infp);
  697.                 fclose(outfp);
  698.                 return;
  699.             }
  700.             if (font_command_write(outfp, &outfc) == ERROR)
  701.             {
  702.                 fprintf(stderr, ERROR_FILE_WRITE_FAILED, os_dir, os_file);
  703.                 ljchar_free_all();
  704.                 fclose(infp);
  705.                 fclose(outfp);
  706.                 return;
  707.             }
  708.             break;
  709.         case CCC:
  710.             charcode = infc.number;
  711.             break;
  712.         case CDC:
  713.             if (ljchar_create(charcode, &infc) == ERROR)
  714.             {
  715.                 ljchar_free_all();
  716.                 fclose(infp);
  717.                 fclose(outfp);
  718.                 return;
  719.             }
  720.             break;
  721.         }
  722.     }
  723.  
  724.     /* copy the pass(es) of a multi-pass font */
  725.     for (pass = 0; pass < npasses && r == EOF; pass++)
  726.     {
  727.         for (charcode = 0; charcode < sizeofarray(ljchars); charcode++)
  728.         {
  729.             if (ljchars[charcode].bitmap != NULL)
  730.             {
  731.                 /* output the character code command */
  732.                 outfc.command_type = CCC;
  733.                 outfc.number = charcode;
  734.                 if (font_command_write(outfp, &outfc) == ERROR)
  735.                 {
  736.                     fprintf(stderr, ERROR_FILE_WRITE_FAILED, os_dir, os_file);
  737.                     ljchar_free_all();
  738.                     fclose(infp);
  739.                     fclose(outfp);
  740.                     return;
  741.                 }
  742.  
  743.                 /* convert the character descriptor and bitmap */
  744.                 if (cdc_lj_to_dj(charcode, &ljchars[charcode], &outfc,
  745.                     npasses == 1?CHAR_TYPE_NORMAL:char_type_for_pass(pass)) == ERROR)
  746.                 {
  747.                     ljchar_free_all();
  748.                     fclose(infp);
  749.                     fclose(outfp);
  750.                     return;
  751.                 }
  752.  
  753.                 /* output the character descriptor and bitmap */
  754.                 if (font_command_write(outfp, &outfc) == ERROR)
  755.                 {
  756.                     fprintf(stderr, ERROR_FILE_WRITE_FAILED, os_dir, os_file);
  757.                     ljchar_free_all();
  758.                     fclose(infp);
  759.                     fclose(outfp);
  760.                     return;
  761.                 }
  762.             }
  763.         }
  764.     }
  765.  
  766.     if (npasses == 0 || r != EOF)
  767.         /* error scenarios: (npasses == 0) means no font descriptor found,
  768.            probably processing a text file; (r != EOF) means a font
  769.            command escape sequence wasn't read in correctly, probably
  770.            processing a binary file or a truncated soft font file */
  771.         fprintf(stderr, ERROR_FILE_READ_FAILED, os_dir, os_file);
  772.     else
  773.     {
  774.         /* give warnings about negative side bearing lost if any */
  775.         if (worst_left_loss < 0)
  776.         {
  777.             if (isascii(worst_left_char) && isprint(worst_left_char))
  778.                 sprintf(worst_char_string, "%c", worst_left_char);
  779.             else
  780.                 sprintf(worst_char_string, "\\%03o", worst_left_char);
  781.  
  782.             fprintf(stderr, WARNING_SIDE_BEARING, os_dir, os_file,
  783.                 "left", worst_left_loss, worst_char_string);
  784.         }
  785.         if (worst_right_loss < 0)
  786.         {
  787.             if (isascii(worst_right_char) && isprint(worst_right_char))
  788.                 sprintf(worst_char_string, "%c", worst_right_char);
  789.             else
  790.                 sprintf(worst_char_string, "\\%03o", worst_right_char);
  791.  
  792.             fprintf(stderr, WARNING_SIDE_BEARING, os_dir, os_file,
  793.                 "right", worst_right_loss, worst_char_string);
  794.         }
  795.         fprintf(stderr, OK_JETL2D, os_dir, os_file, outpath);
  796.     }
  797.  
  798.     ljchar_free_all();
  799.     fclose(infp);
  800.     fclose(outfp);
  801. }
  802.  
  803. main(argc, argv)
  804. int argc;
  805. char *argv[];
  806. {
  807.     char c;
  808.  
  809.     /* stop getopt() printing errors */
  810.     opterr = FALSE;
  811.     while ((c = getopt(argc, argv, "t:hjo")) != EOF)
  812.     {
  813.         switch (c)
  814.         {
  815.         case 't':
  816.             strncpy(output_suffix+1, optarg, SUFFIX_MAX-2);
  817.             output_suffix[SUFFIX_MAX-1] = '\0';
  818.             break;
  819.         case 'o':
  820.             dj500_support = FALSE;
  821.             break;
  822.         case 'j':
  823.             bitmap_optimisation = FALSE;
  824.             break;
  825.         case 'h':
  826.         case '?':
  827.             /* help required, or invalid option specified */
  828.             usage_wrong();
  829.         }
  830.     }
  831.  
  832.     /* must specify at least one file */
  833.     if (optind >= argc)
  834.         usage_wrong();
  835.  
  836.     /* process file arguments */
  837.     if (os_findfiles((argc - optind), &argv[optind]) == ERROR)
  838.         fprintf(stderr, ERROR_OUT_OF_HEAP);
  839.  
  840.     while (os_getfile() != EOF)
  841.         jetl2d();
  842.  
  843.     return(0);
  844. }
  845.